library(circlize)
## ========================================
## circlize version 0.4.9
## CRAN page: https://cran.r-project.org/package=circlize
## Github page: https://github.com/jokergoo/circlize
## Documentation: https://jokergoo.github.io/circlize_book/book/
## 
## If you use it in published research, please cite:
## Gu, Z. circlize implements and enhances circular visualization
##   in R. Bioinformatics 2014.
## 
## This message can be suppressed by:
##   suppressPackageStartupMessages(library(circlize))
## ========================================
library(tidyverse)
## ── Attaching packages ──────────────────────────────────────────────────────── tidyverse 1.3.0 ──
## ✓ ggplot2 3.3.0     ✓ purrr   0.3.4
## ✓ tibble  3.0.1     ✓ dplyr   0.8.5
## ✓ tidyr   1.0.2     ✓ stringr 1.4.0
## ✓ readr   1.3.1     ✓ forcats 0.5.0
## ── Conflicts ─────────────────────────────────────────────────────────── tidyverse_conflicts() ──
## x dplyr::filter() masks stats::filter()
## x dplyr::lag()    masks stats::lag()
library(gt)
library(skimr)
library(officer)
source("01_prep-data.R")
## 
## Attaching package: 'readxl'
## The following object is masked from 'package:officer':
## 
##     read_xlsx
## 
## Attaching package: 'janitor'
## The following objects are masked from 'package:stats':
## 
##     chisq.test, fisher.test
## New names:
## * `` -> ...1
## * `` -> ...2
## * `` -> ...3
## * `` -> ...4
## * `` -> ...5
## * ...
## Parsed with column specification:
## cols(
##   `Global Code` = col_character(),
##   `Global Name` = col_character(),
##   `Region Code` = col_character(),
##   `Region Name` = col_character(),
##   `Sub-region Code` = col_character(),
##   `Sub-region Name` = col_character(),
##   `Intermediate Region Code` = col_character(),
##   `Intermediate Region Name` = col_character(),
##   `Country or Area` = col_character(),
##   `M49 Code` = col_character(),
##   `ISO-alpha3 Code` = col_character(),
##   `Least Developed Countries (LDC)` = col_character(),
##   `Land Locked Developing Countries (LLDC)` = col_character(),
##   `Small Island Developing States (SIDS)` = col_character(),
##   `Developed / Developing Countries` = col_character()
## )
## Warning: 1 parsing failure.
## row col   expected     actual                                                            file
## 118  -- 15 columns 11 columns '/Users/petr/carchive/migration-diagram/data-input/un_list.tsv'
## Warning: NAs introduced by coercion

Načíst data

source("02_prep-colours.R")
## 
## Attaching package: 'magrittr'
## The following object is masked from 'package:purrr':
## 
##     set_names
## The following object is masked from 'package:tidyr':
## 
##     extract
df <- read_rds("data-processed/orig-dest-new.rds")

Upravit data

dfl <- df %>% 
  filter(value > 0) %>% 
  drop_na() %>% 
  select(from = origin, to = destination, value)
dfl

Zkontrolovat, jestli jsou řádky unikátní

distinct(dfl, from, to)

Počet řádků stejný, jako u konečného datasetu, takže fajn.

Vykreslit graf:

circos.clear()
chordDiagram(df)
## There are more than one numeric columns in the data frame. Take the
## first two numeric columns and draw the link ends with unequal width.

Hmm, to vypadá fakt divně a nevím proč. Zkusíme funkci stavěnou na data frame, ne na matici:

circos.clear()
chordDiagramFromDataFrame(dfl, directional = 1)

dfl_filtered <- dfl %>% 
  ungroup() %>% 
  filter(value > 8e4) %>% 
  mutate(value = value/1e5,
         # to = str_replace(to, "Europe", "čáěšžěšéí"),
         # from = str_replace(from, "Europe", "čáěšžěšéí"),
         from = str_replace(from, "South-eastern Asia", "SouthEastern Asia") %>%
           str_wrap(10),
         to = str_replace(to, "South-eastern Asia", "SouthEastern Asia") %>% 
           str_wrap(10))
dfl_filtered
setdiff(dfl_filtered$from, dfl_filtered$to)
## [1] "Caribbean"        "Central\nAmerica" "Central\nAsia"    "Middle\nAfrica"  
## [5] "South\nAmerica"   "Southern\nAsia"   "Southern\nEurope"
setdiff(dfl_filtered$to, dfl_filtered$from)
## [1] "Northern\nAmerica"
scales::show_col(cols, borders = F)

names(cols)
##  [1] "yellow"       "orange"       "wine"         "brown"        "purple"      
##  [6] "blue_light"   "blue_dark"    "green"        "yellow_l"     "orange_l"    
## [11] "wine_l"       "brown_l"      "purple_l"     "blue_light_l" "blue_dark_l" 
## [16] "green_l"
nazevnik <- tribble(~ordered_en, ~ordered_cz, ~color_old, ~color,
                    "Eastern Africa","Východní Afrika","darkgreen",cols[["yellow"]],
                    "Middle Africa","Střední Afrika","chartreuse4",cols[["yellow_l"]],
                    "Northern Africa","Severní Afrika","chartreuse3",cols[["orange"]],
                    "Southern Africa","Jižní Afrika","darkolivegreen",cols[["orange_l"]],
                    "Western Africa","Západní Afrika","darkolivegreen3","#e6bd33",
                    "Central Asia","Střední Asie","blue4",cols[["blue_dark"]],
                    "Eastern Asia","Východní Asie","blue1",cols[["blue_dark_l"]],
                    "Southern Asia","Jižní Asie","cornflowerblue",cols[["blue_light_l"]],
                    "SouthEastern Asia","Jihovýchodní Asie","blue1",cols[["blue_light"]],
                    "Western Asia","Západní Asie","deepskyblue","#023FA5",
                    "Eastern Europe","Východní Evropa","brown3",cols[["brown_l"]],
                    "Northern Europe","Severní Evropa","brown1",cols[["brown"]],
                    "Southern Europe","Jižní Evropa","coral",cols[["purple"]],
                    "Western Europe","Západní Evropa","darkred",cols[["purple_l"]],
                    "Caribbean","Karibik","blueviolet",cols[["wine"]],
                    "Central America","Střední Amerika","darkmagenta",cols[["green_l"]],
                    "South America","Jižní Amerika","darkorchid2","#006600",
                    "Northern America","Severní Amerika","darksalmon",cols[["green"]],
                    "Oceania","Oceánie","deeppink3", cols[["wine_l"]]) %>% 
  mutate(label_wrapped_en = str_wrap(ordered_en, 10),
         label_wrapped_cz = str_wrap(ordered_cz, 10))

setdiff(nazevnik$label_wrapped_en, dfl_filtered$from)
## [1] "Southern\nAfrica"  "Northern\nAmerica" "Oceania"
setdiff(dfl_filtered$from, nazevnik$label_wrapped_en)
## character(0)
setdiff(dfl_filtered$to, nazevnik$label_wrapped_en)
## character(0)
length(unique(nazevnik$label_wrapped_cz)) == length(nazevnik$label_wrapped_cz)
## [1] TRUE
# from https://stackoverflow.com/questions/31943102/rotate-labels-in-a-chorddiagram-r-circlize
make_circle_plot <- function(cz = FALSE) {
  
  barvy_grid <- nazevnik$color
  
  names(barvy_grid) <- if(cz) nazevnik$label_wrapped_cz else
    nazevnik$label_wrapped_en
  
  barvy_links <- dfl_filtered %>% 
    left_join(nazevnik %>% rename(from = label_wrapped_en)) %>% 
    pull(color)
  
  if(cz) {
    plot_data <- dfl_filtered %>% 
      left_join(nazevnik %>% select(from = label_wrapped_en, 
                                    label_wrapped_cz)) %>% 
      select(-from) %>%
      rename(from = label_wrapped_cz) %>% 
      left_join(nazevnik %>% select(to = label_wrapped_en,
                                    label_wrapped_cz)) %>% 
      select(-to) %>%
      rename(to = label_wrapped_cz) %>% 
      select(to, from, value)
  } else {
    plot_data <- dfl_filtered %>% 
      select(to, from, value)
  }
  
  # print(plot_data)
  
  order_list <- if(cz) {nazevnik$label_wrapped_cz
  } else {
    nazevnik$label_wrapped_en
  }
  
  # plot_data$to %in% order_list
  # plot_data$from %in% order_list
  
  par(lheight = .8)
  chordDiagramFromDataFrame(plot_data,
                            directional = -1,
                            diffHeight = uh(-3, "mm"),
                            link.arr.type = "triangle",
                            link.arr.width = .30,
                            link.arr.length = .30,
                            link.arr.lwd = 2,
                            # link.arr.col = barvy_links,
                            link.arr.col = c(rep(NA, 10),
                                             "#853946",
                                             rep(NA, 9),
                                             "#023FA5",
                                             rep(NA, 3),
                                             "#023FA5",
                                             rep(NA, nrow(plot_data)-4-21)),
                            direction.type = "arrows+diffHeight",
                            grid.col = barvy_grid,
                            col = barvy_links,
                            transparency = .2,
                            link.lwd = 2,
                            link.border = "white",
                            order = order_list,
                            annotationTrack = "grid",
                            preAllocateTracks = 1)
  circos.trackPlotRegion(track.index = 1, panel.fun = function(x, y) {
    xlim = get.cell.meta.data("xlim")
    ylim = get.cell.meta.data("ylim")
    sector.name = get.cell.meta.data("sector.index")
    circos.text(mean(xlim), ylim[1] + .4, sector.name,
                facing = "clockwise", niceFacing = TRUE, adj = c(0, 0.5))
    circos.axis(h = "top", labels.cex = 0.5, major.at = seq(0, 100, by = 5),
                sector.index = sector.name, track.index = 2, minor.ticks = 4)
  }, bg.border = NA)
  
  # return(plot_data)
}
make_circle_plot(cz = FALSE)
## Joining, by = "from"

cairo_pdf(file = "chart-output/circle_en.pdf", width = 8, height = 8)
make_circle_plot(cz = FALSE)
## Joining, by = "from"
dev.off()
## quartz_off_screen 
##                 2
make_circle_plot(cz = FALSE)
## Joining, by = "from"

cairo_pdf(file = "chart-output/circle_cz.pdf", width = 8, height = 8)
make_circle_plot(cz = TRUE)
## Joining, by = "from"
## Joining, by = "from"
## Joining, by = "to"
dev.off()
## quartz_off_screen 
##                 2
make_circle_plot(cz = TRUE)
## Joining, by = "from"
## Joining, by = "from"
## Joining, by = "to"

Ostatní formáty

ragg::agg_tiff(filename = "chart-output/circle_en.tiff", 
               width = 297, height = 297, units = "mm", res = 300, pointsize = 16)
make_circle_plot(cz = FALSE)
## Joining, by = "from"
dev.off()
## quartz_off_screen 
##                 2
ragg::agg_tiff(filename = "chart-output/circle_cz.tiff", 
               width = 297, height = 297, units = "mm", res = 300, pointsize = 16)
make_circle_plot(cz = TRUE)
## Joining, by = "from"
## Joining, by = "from"
## Joining, by = "to"
dev.off()
## quartz_off_screen 
##                 2
svglite::svglite(file = "chart-output/circle_cz.svg", width = 8, height = 8)
make_circle_plot(cz = TRUE)
## Joining, by = "from"
## Joining, by = "from"
## Joining, by = "to"
dev.off()
## quartz_off_screen 
##                 2
svglite::svglite(file = "chart-output/circle_en.svg", width = 8, height = 8)
make_circle_plot(cz = FALSE)
## Joining, by = "from"
dev.off()
## quartz_off_screen 
##                 2
devEMF::emf("chart-output/circle_cz.emf")
make_circle_plot(cz = TRUE)
## Joining, by = "from"
## Joining, by = "from"
## Joining, by = "to"
dev.off()
## quartz_off_screen 
##                 2
devEMF::emf("chart-output/circle_en.emf")
make_circle_plot(cz = FALSE)
## Joining, by = "from"
dev.off()
## quartz_off_screen 
##                 2
read_pptx() %>% 
  add_slide() %>% 
  ph_with(location = ph_location_fullsize(),
                   value = plot_instr(code = {make_circle_plot(cz = TRUE)})) %>%
  add_slide() %>% 
  ph_with(location = ph_location_fullsize(),
                   value = external_img("chart-output/circle_en.svg")) %>% 
  add_slide() %>% 
  ph_with(location = ph_location_fullsize(),
                   value = external_img("chart-output/circle_en.emf")) %>% 
  add_slide() %>% 
  ph_with(location = ph_location_fullsize(),
                   value = plot_instr(code = {make_circle_plot(cz = FALSE)})) %>%
  add_slide() %>% 
  ph_with(location = ph_location_fullsize(),
                   value = external_img("chart-output/circle_cz.svg")) %>% 
  add_slide() %>% 
  ph_with(location = ph_location_fullsize(),
                   value = external_img("chart-output/circle_cz.emf")) %>% 
  print(target = "chart-output/charts.pptx")
## Joining, by = "from"
## Joining, by = "from"
## Joining, by = "to"
## Loading required namespace: rsvg
## Joining, by = "from"

Rozdíly mezi verzemi

source("98_use-preprocessed-data.R")
## Using ',' as decimal and '.' as grouping mark. Use read_delim() for more control.
## Parsed with column specification:
## cols(
##   .default = col_double(),
##   DESTINATION = col_character()
## )
## See spec(...) for full column specifications.
compar <- dfl_filtered %>% 
  mutate(flow = paste(to, "to", from)) %>% 
  select(-from, -to) %>% 
  full_join(dflo_filtered %>% 
              mutate(flow = paste(from, "to", to)) %>% 
              select(-from, -to, value_old = value)
  ) %>% 
  replace_na(replace = list(value = 0, value = 0)) %>% 
  select(flow, value_old, value) %>% 
  mutate(diff = value - value_old,
         diff_pct = diff/value) %>% 
  arrange(desc(abs(diff_pct)))
## Joining, by = "flow"
compar
compar %>% 
  gt::gt() %>% 
  fmt_number(2:4, decimals = 1) %>% 
  fmt_percent(5, decimals = 1)
flow value_old value diff diff_pct
South- Eastern Asia to SouthEastern Asia 1.8 0.0 −1.8 −Inf%
South America to South America 1.2 0.0 −1.2 −Inf%
Western Europe to Southern Europe 3.0 2.4 −0.5 −22.2%
Western Europe to Western Europe 1.8 1.5 −0.3 −20.4%
Western Europe to Western Asia 3.6 3.3 −0.3 −8.8%
Western Europe to Eastern Europe 8.5 8.1 −0.3 −4.2%
Western Asia to Northern Africa 2.5 2.4 −0.0 −1.0%
Western Asia to Southern Asia 13.4 13.2 −0.1 −0.9%
Western Asia to SouthEastern Asia 3.5 3.5 −0.0 −0.5%
Western Asia to Western Asia 8.2 8.2 0.0 0.3%
Western Europe to Central Asia 1.9 1.9 −0.0 −0.2%
Northern America to Caribbean 2.1 2.1 0.0 0.0%
Northern America to Eastern Asia 1.8 1.8 0.0 0.0%
Northern America to Southern Asia 1.6 1.6 0.0 0.0%
Northern America to SouthEastern Asia 1.8 1.8 0.0 0.0%
Northern America to South America 1.1 1.1 0.0 0.0%
Northern America to Central America 5.3 5.3 0.0 0.0%
Eastern Africa to Eastern Africa 4.7 4.7 0.0 0.0%
Eastern Asia to Eastern Asia 1.2 1.2 0.0 0.0%
Eastern Europe to Eastern Europe 1.4 1.4 0.0 0.0%
Eastern Africa to Middle Africa 1.2 1.2 0.0 0.0%
Northern Europe to Southern Asia 1.2 1.2 0.0 0.0%
Western Africa to Western Africa 1.2 1.2 0.0 0.0%
Northern Africa to Eastern Africa NA 0.8 NA NA
Northern Europe to Eastern Europe NA 1.0 NA NA
Western Asia to Eastern Europe NA 0.9 NA NA
Northern Europe to Northern Europe NA 0.9 NA NA
SouthEastern Asia to SouthEastern Asia NA 1.8 NA NA
Western Europe to Southern Asia NA 0.8 NA NA
LS0tCnRpdGxlOiAiTWlncmF0aW9uIGNpcmNsZSBkaWFncmFtIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIGRmX3ByaW50OiBwYWdlZAogICAgY29kZV9kb3dubG9hZDogdHJ1ZQotLS0KCmBgYHtyIHNldHVwfQpsaWJyYXJ5KGNpcmNsaXplKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShndCkKbGlicmFyeShza2ltcikKbGlicmFyeShvZmZpY2VyKQpgYGAKCmBgYHtyIHNvdXJjZSBkYXRhIHByZXAgc2NyaXB0fQpzb3VyY2UoIjAxX3ByZXAtZGF0YS5SIikKYGBgCgoKTmHEjcOtc3QgZGF0YQoKYGBge3Igc291cmNlIGNvbG91ciBzY3JpcHR9CnNvdXJjZSgiMDJfcHJlcC1jb2xvdXJzLlIiKQpkZiA8LSByZWFkX3JkcygiZGF0YS1wcm9jZXNzZWQvb3JpZy1kZXN0LW5ldy5yZHMiKQpgYGAKClVwcmF2aXQgZGF0YQoKYGBge3IgZmlsdGVyIGRhdGF9CmRmbCA8LSBkZiAlPiUgCiAgZmlsdGVyKHZhbHVlID4gMCkgJT4lIAogIGRyb3BfbmEoKSAlPiUgCiAgc2VsZWN0KGZyb20gPSBvcmlnaW4sIHRvID0gZGVzdGluYXRpb24sIHZhbHVlKQpgYGAKCgpgYGB7ciBjaGVjayBkYXRhfQpkZmwKYGBgCgpaa29udHJvbG92YXQsIGplc3RsaSBqc291IMWZw6Fka3kgdW5pa8OhdG7DrSAKCmBgYHtyIGNoZWNrIHVuaXF1ZX0KZGlzdGluY3QoZGZsLCBmcm9tLCB0bykKYGBgCgpQb8SNZXQgxZnDoWRrxa8gc3Rlam7DvSwgamFrbyB1IGtvbmXEjW7DqWhvIGRhdGFzZXR1LCB0YWvFvmUgZmFqbi4KClZ5a3Jlc2xpdCBncmFmOgoKYGBge3IgY2hhcnQtb3JpZ30KY2lyY29zLmNsZWFyKCkKY2hvcmREaWFncmFtKGRmKQpgYGAKCgpIbW0sIHRvIHZ5cGFkw6EgZmFrdCBkaXZuxJsgYSBuZXbDrW0gcHJvxI0uIFprdXPDrW1lIGZ1bmtjaSBzdGF2xJtub3UgbmEgZGF0YSBmcmFtZSwgbmUgbmEgbWF0aWNpOgoKYGBge3J9CmNpcmNvcy5jbGVhcigpCmNob3JkRGlhZ3JhbUZyb21EYXRhRnJhbWUoZGZsLCBkaXJlY3Rpb25hbCA9IDEpCmBgYAoKCmBgYHtyIGZpbHRlciBjaG9yZHN9CmRmbF9maWx0ZXJlZCA8LSBkZmwgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgZmlsdGVyKHZhbHVlID4gOGU0KSAlPiUgCiAgbXV0YXRlKHZhbHVlID0gdmFsdWUvMWU1LAogICAgICAgICAjIHRvID0gc3RyX3JlcGxhY2UodG8sICJFdXJvcGUiLCAixI3DocSbxaHFvsSbxaHDqcOtIiksCiAgICAgICAgICMgZnJvbSA9IHN0cl9yZXBsYWNlKGZyb20sICJFdXJvcGUiLCAixI3DocSbxaHFvsSbxaHDqcOtIiksCiAgICAgICAgIGZyb20gPSBzdHJfcmVwbGFjZShmcm9tLCAiU291dGgtZWFzdGVybiBBc2lhIiwgIlNvdXRoRWFzdGVybiBBc2lhIikgJT4lCiAgICAgICAgICAgc3RyX3dyYXAoMTApLAogICAgICAgICB0byA9IHN0cl9yZXBsYWNlKHRvLCAiU291dGgtZWFzdGVybiBBc2lhIiwgIlNvdXRoRWFzdGVybiBBc2lhIikgJT4lIAogICAgICAgICAgIHN0cl93cmFwKDEwKSkKZGZsX2ZpbHRlcmVkCmBgYAoKCmBgYHtyfQpzZXRkaWZmKGRmbF9maWx0ZXJlZCRmcm9tLCBkZmxfZmlsdGVyZWQkdG8pCnNldGRpZmYoZGZsX2ZpbHRlcmVkJHRvLCBkZmxfZmlsdGVyZWQkZnJvbSkKYGBgCgpgYGB7cn0Kc2NhbGVzOjpzaG93X2NvbChjb2xzLCBib3JkZXJzID0gRikKYGBgCgpgYGB7cn0KbmFtZXMoY29scykKYGBgCgoKYGBge3Igb3JkZXJ9Cm5hemV2bmlrIDwtIHRyaWJibGUofm9yZGVyZWRfZW4sIH5vcmRlcmVkX2N6LCB+Y29sb3Jfb2xkLCB+Y29sb3IsCiAgICAgICAgICAgICAgICAgICAgIkVhc3Rlcm4gQWZyaWNhIiwiVsO9Y2hvZG7DrSBBZnJpa2EiLCJkYXJrZ3JlZW4iLGNvbHNbWyJ5ZWxsb3ciXV0sCiAgICAgICAgICAgICAgICAgICAgIk1pZGRsZSBBZnJpY2EiLCJTdMWZZWRuw60gQWZyaWthIiwiY2hhcnRyZXVzZTQiLGNvbHNbWyJ5ZWxsb3dfbCJdXSwKICAgICAgICAgICAgICAgICAgICAiTm9ydGhlcm4gQWZyaWNhIiwiU2V2ZXJuw60gQWZyaWthIiwiY2hhcnRyZXVzZTMiLGNvbHNbWyJvcmFuZ2UiXV0sCiAgICAgICAgICAgICAgICAgICAgIlNvdXRoZXJuIEFmcmljYSIsIkppxb5uw60gQWZyaWthIiwiZGFya29saXZlZ3JlZW4iLGNvbHNbWyJvcmFuZ2VfbCJdXSwKICAgICAgICAgICAgICAgICAgICAiV2VzdGVybiBBZnJpY2EiLCJaw6FwYWRuw60gQWZyaWthIiwiZGFya29saXZlZ3JlZW4zIiwiI2U2YmQzMyIsCiAgICAgICAgICAgICAgICAgICAgIkNlbnRyYWwgQXNpYSIsIlN0xZllZG7DrSBBc2llIiwiYmx1ZTQiLGNvbHNbWyJibHVlX2RhcmsiXV0sCiAgICAgICAgICAgICAgICAgICAgIkVhc3Rlcm4gQXNpYSIsIlbDvWNob2Ruw60gQXNpZSIsImJsdWUxIixjb2xzW1siYmx1ZV9kYXJrX2wiXV0sCiAgICAgICAgICAgICAgICAgICAgIlNvdXRoZXJuIEFzaWEiLCJKacW+bsOtIEFzaWUiLCJjb3JuZmxvd2VyYmx1ZSIsY29sc1tbImJsdWVfbGlnaHRfbCJdXSwKICAgICAgICAgICAgICAgICAgICAiU291dGhFYXN0ZXJuIEFzaWEiLCJKaWhvdsO9Y2hvZG7DrSBBc2llIiwiYmx1ZTEiLGNvbHNbWyJibHVlX2xpZ2h0Il1dLAogICAgICAgICAgICAgICAgICAgICJXZXN0ZXJuIEFzaWEiLCJaw6FwYWRuw60gQXNpZSIsImRlZXBza3libHVlIiwiIzAyM0ZBNSIsCiAgICAgICAgICAgICAgICAgICAgIkVhc3Rlcm4gRXVyb3BlIiwiVsO9Y2hvZG7DrSBFdnJvcGEiLCJicm93bjMiLGNvbHNbWyJicm93bl9sIl1dLAogICAgICAgICAgICAgICAgICAgICJOb3J0aGVybiBFdXJvcGUiLCJTZXZlcm7DrSBFdnJvcGEiLCJicm93bjEiLGNvbHNbWyJicm93biJdXSwKICAgICAgICAgICAgICAgICAgICAiU291dGhlcm4gRXVyb3BlIiwiSmnFvm7DrSBFdnJvcGEiLCJjb3JhbCIsY29sc1tbInB1cnBsZSJdXSwKICAgICAgICAgICAgICAgICAgICAiV2VzdGVybiBFdXJvcGUiLCJaw6FwYWRuw60gRXZyb3BhIiwiZGFya3JlZCIsY29sc1tbInB1cnBsZV9sIl1dLAogICAgICAgICAgICAgICAgICAgICJDYXJpYmJlYW4iLCJLYXJpYmlrIiwiYmx1ZXZpb2xldCIsY29sc1tbIndpbmUiXV0sCiAgICAgICAgICAgICAgICAgICAgIkNlbnRyYWwgQW1lcmljYSIsIlN0xZllZG7DrSBBbWVyaWthIiwiZGFya21hZ2VudGEiLGNvbHNbWyJncmVlbl9sIl1dLAogICAgICAgICAgICAgICAgICAgICJTb3V0aCBBbWVyaWNhIiwiSmnFvm7DrSBBbWVyaWthIiwiZGFya29yY2hpZDIiLCIjMDA2NjAwIiwKICAgICAgICAgICAgICAgICAgICAiTm9ydGhlcm4gQW1lcmljYSIsIlNldmVybsOtIEFtZXJpa2EiLCJkYXJrc2FsbW9uIixjb2xzW1siZ3JlZW4iXV0sCiAgICAgICAgICAgICAgICAgICAgIk9jZWFuaWEiLCJPY2XDoW5pZSIsImRlZXBwaW5rMyIsIGNvbHNbWyJ3aW5lX2wiXV0pICU+JSAKICBtdXRhdGUobGFiZWxfd3JhcHBlZF9lbiA9IHN0cl93cmFwKG9yZGVyZWRfZW4sIDEwKSwKICAgICAgICAgbGFiZWxfd3JhcHBlZF9jeiA9IHN0cl93cmFwKG9yZGVyZWRfY3osIDEwKSkKCnNldGRpZmYobmF6ZXZuaWskbGFiZWxfd3JhcHBlZF9lbiwgZGZsX2ZpbHRlcmVkJGZyb20pCnNldGRpZmYoZGZsX2ZpbHRlcmVkJGZyb20sIG5hemV2bmlrJGxhYmVsX3dyYXBwZWRfZW4pCnNldGRpZmYoZGZsX2ZpbHRlcmVkJHRvLCBuYXpldm5payRsYWJlbF93cmFwcGVkX2VuKQoKYGBgCgpgYGB7cn0KbGVuZ3RoKHVuaXF1ZShuYXpldm5payRsYWJlbF93cmFwcGVkX2N6KSkgPT0gbGVuZ3RoKG5hemV2bmlrJGxhYmVsX3dyYXBwZWRfY3opCmBgYAoKCmBgYHtyIHBsb3R0aW5nIGZ1bmN0aW9ufQojIGZyb20gaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMzE5NDMxMDIvcm90YXRlLWxhYmVscy1pbi1hLWNob3JkZGlhZ3JhbS1yLWNpcmNsaXplCm1ha2VfY2lyY2xlX3Bsb3QgPC0gZnVuY3Rpb24oY3ogPSBGQUxTRSkgewogIAogIGJhcnZ5X2dyaWQgPC0gbmF6ZXZuaWskY29sb3IKICAKICBuYW1lcyhiYXJ2eV9ncmlkKSA8LSBpZihjeikgbmF6ZXZuaWskbGFiZWxfd3JhcHBlZF9jeiBlbHNlCiAgICBuYXpldm5payRsYWJlbF93cmFwcGVkX2VuCiAgCiAgYmFydnlfbGlua3MgPC0gZGZsX2ZpbHRlcmVkICU+JSAKICAgIGxlZnRfam9pbihuYXpldm5payAlPiUgcmVuYW1lKGZyb20gPSBsYWJlbF93cmFwcGVkX2VuKSkgJT4lIAogICAgcHVsbChjb2xvcikKICAKICBpZihjeikgewogICAgcGxvdF9kYXRhIDwtIGRmbF9maWx0ZXJlZCAlPiUgCiAgICAgIGxlZnRfam9pbihuYXpldm5payAlPiUgc2VsZWN0KGZyb20gPSBsYWJlbF93cmFwcGVkX2VuLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxfd3JhcHBlZF9jeikpICU+JSAKICAgICAgc2VsZWN0KC1mcm9tKSAlPiUKICAgICAgcmVuYW1lKGZyb20gPSBsYWJlbF93cmFwcGVkX2N6KSAlPiUgCiAgICAgIGxlZnRfam9pbihuYXpldm5payAlPiUgc2VsZWN0KHRvID0gbGFiZWxfd3JhcHBlZF9lbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxfd3JhcHBlZF9jeikpICU+JSAKICAgICAgc2VsZWN0KC10bykgJT4lCiAgICAgIHJlbmFtZSh0byA9IGxhYmVsX3dyYXBwZWRfY3opICU+JSAKICAgICAgc2VsZWN0KHRvLCBmcm9tLCB2YWx1ZSkKICB9IGVsc2UgewogICAgcGxvdF9kYXRhIDwtIGRmbF9maWx0ZXJlZCAlPiUgCiAgICAgIHNlbGVjdCh0bywgZnJvbSwgdmFsdWUpCiAgfQogIAogICMgcHJpbnQocGxvdF9kYXRhKQogIAogIG9yZGVyX2xpc3QgPC0gaWYoY3opIHtuYXpldm5payRsYWJlbF93cmFwcGVkX2N6CiAgfSBlbHNlIHsKICAgIG5hemV2bmlrJGxhYmVsX3dyYXBwZWRfZW4KICB9CiAgCiAgIyBwbG90X2RhdGEkdG8gJWluJSBvcmRlcl9saXN0CiAgIyBwbG90X2RhdGEkZnJvbSAlaW4lIG9yZGVyX2xpc3QKICAKICBwYXIobGhlaWdodCA9IC44KQogIGNob3JkRGlhZ3JhbUZyb21EYXRhRnJhbWUocGxvdF9kYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uYWwgPSAtMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpZmZIZWlnaHQgPSB1aCgtMywgIm1tIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaW5rLmFyci50eXBlID0gInRyaWFuZ2xlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmsuYXJyLndpZHRoID0gLjMwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGluay5hcnIubGVuZ3RoID0gLjMwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGluay5hcnIubHdkID0gMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgbGluay5hcnIuY29sID0gYmFydnlfbGlua3MsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaW5rLmFyci5jb2wgPSBjKHJlcChOQSwgMTApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiIzg1Mzk0NiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcChOQSwgOSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIjMDIzRkE1IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwKE5BLCAzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiMwMjNGQTUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXAoTkEsIG5yb3cocGxvdF9kYXRhKS00LTIxKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24udHlwZSA9ICJhcnJvd3MrZGlmZkhlaWdodCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmlkLmNvbCA9IGJhcnZ5X2dyaWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2wgPSBiYXJ2eV9saW5rcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zcGFyZW5jeSA9IC4yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGluay5sd2QgPSAyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGluay5ib3JkZXIgPSAid2hpdGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JkZXIgPSBvcmRlcl9saXN0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvblRyYWNrID0gImdyaWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJlQWxsb2NhdGVUcmFja3MgPSAxKQogIGNpcmNvcy50cmFja1Bsb3RSZWdpb24odHJhY2suaW5kZXggPSAxLCBwYW5lbC5mdW4gPSBmdW5jdGlvbih4LCB5KSB7CiAgICB4bGltID0gZ2V0LmNlbGwubWV0YS5kYXRhKCJ4bGltIikKICAgIHlsaW0gPSBnZXQuY2VsbC5tZXRhLmRhdGEoInlsaW0iKQogICAgc2VjdG9yLm5hbWUgPSBnZXQuY2VsbC5tZXRhLmRhdGEoInNlY3Rvci5pbmRleCIpCiAgICBjaXJjb3MudGV4dChtZWFuKHhsaW0pLCB5bGltWzFdICsgLjQsIHNlY3Rvci5uYW1lLAogICAgICAgICAgICAgICAgZmFjaW5nID0gImNsb2Nrd2lzZSIsIG5pY2VGYWNpbmcgPSBUUlVFLCBhZGogPSBjKDAsIDAuNSkpCiAgICBjaXJjb3MuYXhpcyhoID0gInRvcCIsIGxhYmVscy5jZXggPSAwLjUsIG1ham9yLmF0ID0gc2VxKDAsIDEwMCwgYnkgPSA1KSwKICAgICAgICAgICAgICAgIHNlY3Rvci5pbmRleCA9IHNlY3Rvci5uYW1lLCB0cmFjay5pbmRleCA9IDIsIG1pbm9yLnRpY2tzID0gNCkKICB9LCBiZy5ib3JkZXIgPSBOQSkKICAKICAjIHJldHVybihwbG90X2RhdGEpCn0KbWFrZV9jaXJjbGVfcGxvdChjeiA9IEZBTFNFKQpgYGAKCgpgYGB7ciBwbG90LWVufQpjYWlyb19wZGYoZmlsZSA9ICJjaGFydC1vdXRwdXQvY2lyY2xlX2VuLnBkZiIsIHdpZHRoID0gOCwgaGVpZ2h0ID0gOCkKbWFrZV9jaXJjbGVfcGxvdChjeiA9IEZBTFNFKQpkZXYub2ZmKCkKbWFrZV9jaXJjbGVfcGxvdChjeiA9IEZBTFNFKQpgYGAKCmBgYHtyIHBsb3QtY3p9CmNhaXJvX3BkZihmaWxlID0gImNoYXJ0LW91dHB1dC9jaXJjbGVfY3oucGRmIiwgd2lkdGggPSA4LCBoZWlnaHQgPSA4KQptYWtlX2NpcmNsZV9wbG90KGN6ID0gVFJVRSkKZGV2Lm9mZigpCm1ha2VfY2lyY2xlX3Bsb3QoY3ogPSBUUlVFKQpgYGAKCiMjIE9zdGF0bsOtIGZvcm3DoXR5CgpgYGB7ciB0aWZmLXBsb3QtZW59CnJhZ2c6OmFnZ190aWZmKGZpbGVuYW1lID0gImNoYXJ0LW91dHB1dC9jaXJjbGVfZW4udGlmZiIsIAogICAgICAgICAgICAgICB3aWR0aCA9IDI5NywgaGVpZ2h0ID0gMjk3LCB1bml0cyA9ICJtbSIsIHJlcyA9IDMwMCwgcG9pbnRzaXplID0gMTYpCm1ha2VfY2lyY2xlX3Bsb3QoY3ogPSBGQUxTRSkKZGV2Lm9mZigpCmBgYAoKYGBge3IgdGlmZi1wbG90LWN6fQpyYWdnOjphZ2dfdGlmZihmaWxlbmFtZSA9ICJjaGFydC1vdXRwdXQvY2lyY2xlX2N6LnRpZmYiLCAKICAgICAgICAgICAgICAgd2lkdGggPSAyOTcsIGhlaWdodCA9IDI5NywgdW5pdHMgPSAibW0iLCByZXMgPSAzMDAsIHBvaW50c2l6ZSA9IDE2KQptYWtlX2NpcmNsZV9wbG90KGN6ID0gVFJVRSkKZGV2Lm9mZigpCmBgYAoKYGBge3Igc3ZnLXBsb3R9CnN2Z2xpdGU6OnN2Z2xpdGUoZmlsZSA9ICJjaGFydC1vdXRwdXQvY2lyY2xlX2N6LnN2ZyIsIHdpZHRoID0gOCwgaGVpZ2h0ID0gOCkKbWFrZV9jaXJjbGVfcGxvdChjeiA9IFRSVUUpCmRldi5vZmYoKQoKc3ZnbGl0ZTo6c3ZnbGl0ZShmaWxlID0gImNoYXJ0LW91dHB1dC9jaXJjbGVfZW4uc3ZnIiwgd2lkdGggPSA4LCBoZWlnaHQgPSA4KQptYWtlX2NpcmNsZV9wbG90KGN6ID0gRkFMU0UpCmRldi5vZmYoKQpgYGAKCmBgYHtyIGVtZi1wbG90fQpkZXZFTUY6OmVtZigiY2hhcnQtb3V0cHV0L2NpcmNsZV9jei5lbWYiKQptYWtlX2NpcmNsZV9wbG90KGN6ID0gVFJVRSkKZGV2Lm9mZigpCgpkZXZFTUY6OmVtZigiY2hhcnQtb3V0cHV0L2NpcmNsZV9lbi5lbWYiKQptYWtlX2NpcmNsZV9wbG90KGN6ID0gRkFMU0UpCmRldi5vZmYoKQpgYGAKCgpgYGB7ciBwcHR4fQpyZWFkX3BwdHgoKSAlPiUgCiAgYWRkX3NsaWRlKCkgJT4lIAogIHBoX3dpdGgobG9jYXRpb24gPSBwaF9sb2NhdGlvbl9mdWxsc2l6ZSgpLAogICAgICAgICAgICAgICAgICAgdmFsdWUgPSBwbG90X2luc3RyKGNvZGUgPSB7bWFrZV9jaXJjbGVfcGxvdChjeiA9IFRSVUUpfSkpICU+JQogIGFkZF9zbGlkZSgpICU+JSAKICBwaF93aXRoKGxvY2F0aW9uID0gcGhfbG9jYXRpb25fZnVsbHNpemUoKSwKICAgICAgICAgICAgICAgICAgIHZhbHVlID0gZXh0ZXJuYWxfaW1nKCJjaGFydC1vdXRwdXQvY2lyY2xlX2VuLnN2ZyIpKSAlPiUgCiAgYWRkX3NsaWRlKCkgJT4lIAogIHBoX3dpdGgobG9jYXRpb24gPSBwaF9sb2NhdGlvbl9mdWxsc2l6ZSgpLAogICAgICAgICAgICAgICAgICAgdmFsdWUgPSBleHRlcm5hbF9pbWcoImNoYXJ0LW91dHB1dC9jaXJjbGVfZW4uZW1mIikpICU+JSAKICBhZGRfc2xpZGUoKSAlPiUgCiAgcGhfd2l0aChsb2NhdGlvbiA9IHBoX2xvY2F0aW9uX2Z1bGxzaXplKCksCiAgICAgICAgICAgICAgICAgICB2YWx1ZSA9IHBsb3RfaW5zdHIoY29kZSA9IHttYWtlX2NpcmNsZV9wbG90KGN6ID0gRkFMU0UpfSkpICU+JQogIGFkZF9zbGlkZSgpICU+JSAKICBwaF93aXRoKGxvY2F0aW9uID0gcGhfbG9jYXRpb25fZnVsbHNpemUoKSwKICAgICAgICAgICAgICAgICAgIHZhbHVlID0gZXh0ZXJuYWxfaW1nKCJjaGFydC1vdXRwdXQvY2lyY2xlX2N6LnN2ZyIpKSAlPiUgCiAgYWRkX3NsaWRlKCkgJT4lIAogIHBoX3dpdGgobG9jYXRpb24gPSBwaF9sb2NhdGlvbl9mdWxsc2l6ZSgpLAogICAgICAgICAgICAgICAgICAgdmFsdWUgPSBleHRlcm5hbF9pbWcoImNoYXJ0LW91dHB1dC9jaXJjbGVfY3ouZW1mIikpICU+JSAKICBwcmludCh0YXJnZXQgPSAiY2hhcnQtb3V0cHV0L2NoYXJ0cy5wcHR4IikKYGBgCgojIyBSb3pkw61seSBtZXppIHZlcnplbWkKCmBgYHtyfQpzb3VyY2UoIjk4X3VzZS1wcmVwcm9jZXNzZWQtZGF0YS5SIikKCmNvbXBhciA8LSBkZmxfZmlsdGVyZWQgJT4lIAogIG11dGF0ZShmbG93ID0gcGFzdGUodG8sICJ0byIsIGZyb20pKSAlPiUgCiAgc2VsZWN0KC1mcm9tLCAtdG8pICU+JSAKICBmdWxsX2pvaW4oZGZsb19maWx0ZXJlZCAlPiUgCiAgICAgICAgICAgICAgbXV0YXRlKGZsb3cgPSBwYXN0ZShmcm9tLCAidG8iLCB0bykpICU+JSAKICAgICAgICAgICAgICBzZWxlY3QoLWZyb20sIC10bywgdmFsdWVfb2xkID0gdmFsdWUpCiAgKSAlPiUgCiAgcmVwbGFjZV9uYShyZXBsYWNlID0gbGlzdCh2YWx1ZSA9IDAsIHZhbHVlID0gMCkpICU+JSAKICBzZWxlY3QoZmxvdywgdmFsdWVfb2xkLCB2YWx1ZSkgJT4lIAogIG11dGF0ZShkaWZmID0gdmFsdWUgLSB2YWx1ZV9vbGQsCiAgICAgICAgIGRpZmZfcGN0ID0gZGlmZi92YWx1ZSkgJT4lIAogIGFycmFuZ2UoZGVzYyhhYnMoZGlmZl9wY3QpKSkKY29tcGFyCmBgYAoKCmBgYHtyfQpjb21wYXIgJT4lIAogIGd0OjpndCgpICU+JSAKICBmbXRfbnVtYmVyKDI6NCwgZGVjaW1hbHMgPSAxKSAlPiUgCiAgZm10X3BlcmNlbnQoNSwgZGVjaW1hbHMgPSAxKQpgYGAKCgo=